/**
 * @author luzeyu & liangqiaowei
 */
package tiei.ajp.huffman.utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class BitOutputStream {
    private BufferedOutputStream output;
    private int currentByte; // Data of current byte, -1 for EOF
    private int bitPosition; // Next bit index [0...7] to write to
    private long bitCounter; // Num of bits that have read

    public static final int EOF = -1;
    public static final int BIT_O = 0;
    public static final int BIT_1 = 1;
    private static final int HSB_MASK = 0b10000000000000000000000000000000;
    private static final int HSB_UMASK = 0b01111111111111111111111111111111;
    private static final int LSB_MASK = 0b00000000000000000000000000000001;

    public BitOutputStream(File file) throws IOException {
        output = new BufferedOutputStream(new FileOutputStream(file));
        currentByte = 0;
        bitPosition = 0;
        bitCounter = 0L;
    }

    public BitOutputStream(BufferedOutputStream outBf) throws IOException {
        output = outBf;
        currentByte = 0;
        bitPosition = 0;
        bitCounter = 0L;
    }

    public void writeBit(int bit) throws IOException {
        assert bit == BIT_O || bit == BIT_1;

        int bitInHSB = (bit == BIT_1) ? 0b10000000 : 0;

//        // Move right && set HSB to 0
//        currentByte = currentByte >> 1;
//        currentByte &= HSB_UMASK;
//        // Set HSB

        currentByte = currentByte | (bitInHSB >> bitPosition);

        bitPosition++;

        // Check if written full byte
        if (bitPosition == 8) { // 写满一个字节，写入文件并重置
            output.write(currentByte);
            currentByte = 0;
            bitPosition = 0;
        }

        bitCounter++;
    }

    public long getWrittenBitsNum() {
        return bitCounter;
    }

    public void flush() throws IOException {
        // Check if existing bits left to write
        if (bitPosition > 0) {
            // Existing bits left to write, write full byte
            output.write(currentByte);
        }
        output.flush();
    }

    // 关闭流时需要检查是否有未写完的字节
    public void close() throws IOException {
        this.flush();
        output.close();
    }
}

